package dsc;

import java.io.IOException;
import java.util.Vector;
import java.util.List;
import java.util.logging.Logger;
import java.util.Random;

/**
 * De pinger thread kijkt welke apparaten actief zijn. Voor alle geregistreerde
 * apparaten wordt gecontroleerd of hun laatste pingtijd ouder is dan het ping
 * interval. - Als dat het geval is zal er een ping bericht gestuurd worden via
 * de MessageCreator en wordt de ping count verhoogd. - Als de pingtijd
 * verstreken is, wordt er gekeken naar de pongtijd. Als beide verstreken zijn, 
 * krijgt het apparaat 3 kansen om op tijd te pongen Als de tijden verstreken
 * zijn en er 3 keer gepind is, zal het apparaat verwijderd worden en zal het
 * bijbehorende bericht verstuurd worden naar de andere apparaten.
 *  
 */
public class Pinger extends Thread {

    private long pongTime = 2;
    private long pingTime = 10;
    MessageCreator creator;

    public Pinger(MessageCreator creator) {
        this.creator = creator;
    }
     private synchronized String randomPingMessage(){
        Random r = new Random();
        /*we willen wat randomgetallen sturen om het uniek te maken*/
        return Integer.toString(r.nextInt()%99999999);
    }

    /*******
     * Nieuwe pinger methode kijk of pingtijd niet verstreken is kijk of pong
     * tijd verstreken is kijk of pingcount gelijk is aan 3 zo ja, verwijder
     * apparaat en stuur death message als pingcount kleiner dan 3 stuur ping &
     * verhoog pingcount & geef pong twee seconden tijd als pong tijd niet
     * verstreken is ga verder
     *
     * als ping wel verstreken is zo ja, verstuur nieuwe ping & set pingcount 1
     *
     *
     *
     *******/
    /**
     * de Pinger thread
     *
     * @param args
     */
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        DataStorage ds = new DataStorage();
        String name = "";
        Clients client;

        /**
         * Maak logger aan voor de Pinger klasse
         */
        Logging logI = new Logging(Pinger.class.getName());
        Logger logger = logI.createLogger();

        try {
            logI.init(logger);
            /* Wait for server init */
            Thread.sleep(12000);
        } catch (Exception e) {
        }

        logger.info("Pinger has started");

        while (!isInterrupted()) {

            try {
                Thread.sleep(50);
            } catch (Exception e) {
                logger.warning("Slapen van pingerthread mislukt. ");
            }

            /* Zolang er apparaten zijn */
            if (ds.getDevices().size() != 0) {
                Vector<ConnectedDevices> conndevices = ds.getActiveDevices();

                for (ConnectedDevices device : conndevices) {
                    /*
                     * Ga de lijst met apparaten na en check de ping tijden Kijk
                     * of pingtijd niet verstreken is
                     */

                    if (device.getPing() > ((System.currentTimeMillis() / 1000) - pingTime)) {

                        /* Kijk of de pongtijd verstreken is */
                        if ((device.getPing() - device.getPong()) > pongTime) {
                            logger.info("Pongtijd van device is te laat.");

                            /* Bij 3 keer geen gehoor: apparaat is dood */
                            if (device.getPingcount() == 3) {
                                logger.warning("Ping is al 3x gemist, "
                                        + "hij is dood!");
                                /*
                                 * Stuur bericht dat apparaat dood is met
                                 * ipadres client ophalen, client verwijderen,
                                 * door alle conn devices gaan en 130 versturen
                                 */
                                try {
                                    List list = ds.getDevices();

                                    if (device.isServer()) {
                                        /*
                                         * delete server CD and all clients with
                                         * this hop Clients
                                         */
                                    	device.setStatus(false);

                                        creator.msg603(Main.csAddress, 2001,
                                                device.getTag().getBytes());
                                        /*
                                         * We verwijderen pas alle clienten
                                         * wanneer we weer de 604 terug krijgen
                                         * van de control server.
                                         */
//                                        ds.deleteDevice(device);
//                                        ds.removeClientsConnectedToServer(device);
                                        
                                    } else {
                                    	logger.severe("clients verwijderen, omdat hij niet terug pingt");
                                        client = ds.getClient(device.getIpadress(), device.getPort());
                                        name = client.getName();
                                        /*
                                         * delete client from ConnectedDevices
                                         * and Clients
                                         */     
                                        /* voor de zekerheid.*/
                                        device.setStatus(false);
                                        ds.deleteClient(ds.getClient(name));
                                        ds.deleteDevice(device);
                                        
                                        for (int i = 0; i < list.size(); i++) {
                                            creator.msg130(
                                                    ((ConnectedDevices) list.get(i)), name.getBytes());
                                        }
                                    }

                                } catch (Exception e1) {
                                    logger.severe("Kan het apparaat niet vinden");
                                    continue;
                                }

                                logger.severe("Apparaat @ "
                                        + device.getIpadress() + ":"
                                        + device.getPort() + " is dood! OMG!");
                                break;

                            } else {
                                /*
                                 * Pong is te laat, maar pingcount kleiner dan
                                 * 3: stuur ping en update ping count
                                 */
                                try {
                                    ds.setPingCount(device);
                                } catch (Exception e) {
                                }
                                /* Stuur een nieuwe ping naar de device */
                                creator.msg140(device, randomPingMessage().getBytes());
//                                device.setPing(System.currentTimeMillis() / 1000);
                                /* hou de ping tijd gelijk en verschuif je pong 
                                 * tijd naar de toekomst waardoor het meer tijd 
                                 * heeft.
                                 */
                                device.setPong(device.getPing() + pongTime);
                                logger.warning("Pingcount verhoogd van: "
                                        + device.getIpadress() + ":"
                                        + device.getPort() + ", naar: "
                                        + device.getPingcount());
                                logger.info("Ping verstuurd naar: "
                                        + device.getIpadress() + ":"
                                        + device.getPort());
                                continue;
                            }
                        } else {
                            /* Ping- en pong tijd zijn niet verstreken */
                            continue;
                        }
                    } else {
                        /* Ping tijd verstreken, ping het apparaat */
                        creator.msg140(device, randomPingMessage().getBytes());
                        device.setPing(System.currentTimeMillis() / 1000);
//                        device.setPingcount(1);
                        logger.info("Pingtijd verstreken, " + ""
                                + "ping verstuurd naar: "
                                + device.getIpadress() + ":"
                                + device.getPort());
                    }
                }
            }
        }
    }
}
